package Day_0216.JVM.GarbageCollection;

/**
 * @author zxc
 * @date 2023/02/16 17:03
 **/
public class Trigger_FullGC {
    public static void main(String[] args) {
        /**
         * 在什么情况下，会触发Full GC
         * ===>
         * 除直接调用System.gc外，触发Full GC执行的情况有如下四种。
         * 1.旧生代空间不足
         * （1）新生代对象转入老年代/大对象、大数组存储如老年代时，老年代才会出现内存不足的现象，
         * （2）当执行Full GC后空间仍然不足，则抛出如下错误：
         *  java.lang.OutOfMemoryError: Java heap space
         * （3）解决方法 ：
         *  为避免以上两种状况引起的FullGC，调优时应尽量做到让对象在Minor GC阶段被回收;
         *  让对象在新生代多存活一段时间及不要创建过大的对象及数组。
         *
         * 2.永久代（Permanent Generation）空间满
         * （1）Permanent Generation中，存放的是一些class的信息等，
         * （2）当系统中要加载的类、反射的类和调用的方法较多时，Permanent Generation可能会被占满，
         *  在未配置为采用CMS GC的情况下，会执行Full GC。
         *  如果经过Full GC仍然回收不了，那么JVM会抛出如下错误信息：
         *  java.lang.OutOfMemoryError: PermGen space
         * （3）解决方法 ：
         *  为避免Perm Gen占满造成Full GC现象，可采用的方法为增大Perm Gen空间或转为使用CMS GC。
         *
         * 3.CMS GC时，出现promotion failed和concurrent mode failure
         * （1）对于采用CMS进行老生代GC的程序而言，尤其要注意GC日志中是否有promotion failed和concurrent mode failure两种状况，
         *  当这两种状况出现时可能会触发Full GC。
         * （2）promotion failed，是在进行Minor GC时，survivor space放不下，对象只能放入老生代，而此时老生代也放不下造成的；
         * （3）concurrent mode failure是，在执行CMS GC的过程中，同时有对象要放入老生代，而此时老生代空间不足造成的。
         * （4）应对措施为：
         *  增大survivor space、老生代空间或调低触发并发GC的比率，
         *  但在JDK 5.0+、6.0+的版本中有可能会由于JDK的bug29导致CMS在remark完毕后很久才触发sweeping动作。
         *  对于这种状况，可通过设置-XX:CMSMaxAbortablePrecleanTime=5（单位为ms）来避免。
         *
         * 4.统计得到 Minor GC晋升到老年代的平均大小 大于 旧生代的剩余空间
         * （1）这是一个较为复杂的触发情况，Hotspot为了避免由于新生代对象晋升到旧生代导致旧生代空间不足的现象，
         * 在进行Minor GC时，如果之前统计所得到的Minor GC晋升到旧生代的平均大小 大于 旧生代的剩余空间，那么就直接触发Full GC。
         * 例如 ：程序第一次触发Minor GC后，有6MB的对象晋升到旧生代，
         * 那么当下一次Minor GC发生时，首先检查旧生代的剩余空间是否大于6MB，如果小于6MB，则执行Full GC。
         *
         * （2）当新生代采用PS GC时，方式稍有不同，PS GC是在Minor GC后也会检查，
         *  例如 ：上面的例子中，第一次Minor GC后，PS GC会检查此时旧生代的剩余空间是否大于6MB，如小于，则触发对旧生代的回收。
         *
         *
         * 5.除了以上4种状况外，对于使用RMI来进行RPC或管理的Sun JDK应用而言，默认情况下会一小时执行一次Full GC。
         * 可通过在启动时通过- java -D sun.rmi.dgc.client.gcInterval=3600000来设置Full GC执行的间隔时间
         * /或通过-XX:+ DisableExplicitGC，来禁止RMI调用System.gc
         *
         * ===》
         * 总结 ：
         * 触发Full GC的情况 ：
         * （1）系统调用Full GC方法，去执行Full GC;
         * （2）老年代空间不足 ：
         *  即，Minor GC过程中，将新生代对象移动到老年代/新生代中有大对象，大数组，导致直接移动到老年代中，从而导致老年代内存空间不足;
         * （3）永久代空间不足 ：
         *  即，永久代中存储过多的class类信息，导致永久代内存溢出，从而会导致Full GC的发生;
         * （4）CMS GC过程中，报promotion failed || concurrent mode failure错误;
         *  a.promotion failed ：
         *  即，在进行Minor GC时，Survivor区存储不下新对象，新对象只能够被放入到老年代中，同时老年代内存空间也是已经满了;
         *  b.concurrent mode faliure ：
         *  即，在执行CMS GC过程中，同时有对象被放入到老年代中，同时老年代中内存空间也是已经满了的;
         * （5）在进行Minor GC之前，会去估算 之前每次Minor GC时，从新生代转移到老年代对象的平均大小，
         *  若是其 大于老年代剩余内存空间的话，则会直接触发Full GC;
         *
         */
    }
}
